#include "ipc.h"
//进程自定义的键盘中断信号处理函数原型
typedef void (*sighandler_t) (int);
void sigcat(void);
//收到中断信号后释放申请的IPC
void sigcat(){
	struct msqid_ds msg_ds;
	msgctl(q_sofa_id,IPC_RMID,&msg_ds);
	msgctl(q_wait_id,IPC_RMID,&msg_ds);
	semctl(s_customer_id,0,IPC_RMID);
	semctl(s_account_id,0,IPC_RMID);
	exit(0);
}
void work(){
	Msg_buf msg;
	int res;	
	while(1)
	{	
		printf("%d号理发师睡眠\n",getpid());//则理发师进程在沙发队列上睡眠
		msgrcv(q_sofa_id,&msg,sizeof(msg),SOFAQUEST,0);//以阻塞方式从沙发队列接收一条消息
		printf("%d号理发师为%d号顾客理发\n",getpid(),msg.mid);
		up(s_customer_id);//唤醒顾客进程(让下一顾客坐入沙发)
		srand((unsigned) time(NULL)); //用时间做种，每次产生随机数不一样
		sleep(rand()%5+5);//用进程休眠一个随机时间模拟理发过程
		//理完发，使用账本信号量记账
		down(s_account_id);//互斥的获取账本
		printf("%d号理发师收取%d号顾客交费\n",getpid(),msg.mid);//记账
		up(s_account_id);//唤醒用账本理发师者
		//否则没有消息(沙发上无顾客)
		//当沙发队列有消息时被唤醒		
	}
}
void create_process(int n)
{
	int pid;
	int status;
	pid=fork();
	if(pid<0)
	{
		perror("fork error!");
		exit(EXIT_FAILURE);
	}else if(pid==0)
	{
		work();
	}else{
		if(n==1){
			waitpid(pid,&status,0);	//等待子进程结束;
		}else{
			create_process(n-1);
		}
	}
}
int main(){
	init();
	signal(SIGINT,(sighandler_t)sigcat);//注册一个本进程处理键盘中断的函数
	//建立一个同步顾客信号量 s_customer 初值为0  在init中建立
	//建立沙发消息队列 q_sofa,在init中建立
	//建立等候室消息队列 q_wait，在init中建立
	//建立一个互斥账本信号量 s_account,初值为1,在init中建立
	create_process(3);//建立三个理发师进程
	return 0;
}
